home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / httrack-3.30.exe / {app} / src / htsname.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-10-11  |  45.0 KB  |  1,337 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       savename routine (compute output filename)             */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. #include "htsname.h"
  39.  
  40. /* specific definitions */
  41. #include "htsbase.h"
  42. #include "htstools.h"
  43. #include "htsmd5.h"
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <ctype.h>
  47. /* END specific definitions */
  48.  
  49. #undef test_flush
  50. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  51.  
  52. #define ADD_STANDARD_PATH \
  53.     {  /* ajout nom */\
  54.       char buff[HTS_URLMAXSIZE*2];\
  55.       buff[0]='\0';\
  56.       strncatbuff(buff,start_pos,(int) (nom_pos - start_pos));\
  57.       url_savename_addstr(save,buff);\
  58.     }
  59.  
  60. #define ADD_STANDARD_NAME(shortname) \
  61.     {  /* ajout nom */\
  62.       char buff[HTS_URLMAXSIZE*2];\
  63.       standard_name(buff,dot_pos,nom_pos,fil_complete,(shortname));\
  64.       url_savename_addstr(save,buff);\
  65.     }
  66.  
  67.  
  68. /* Avoid stupid DOS system folders/file such as 'nul' */
  69. /* Based on linux/fs/umsdos/mangle.c */
  70. static const char *hts_tbdev[] =
  71. {
  72.     "/prn", "/con", "/aux", "/nul",
  73.     "/lpt1", "/lpt2", "/lpt3", "/lpt4",
  74.     "/com1", "/com2", "/com3", "/com4",
  75.     "/clock$",
  76.     "/emmxxxx0", "/xmsxxxx0", "/setverxx",
  77.     ""
  78. };
  79.  
  80.  
  81.  
  82. // forme le nom du fichier α sauver (save) α partir de fil et adr
  83. // systΦme intelligent, qui renomme en cas de besoin (exemple: deux INDEX.HTML et index.html)
  84. int url_savename(char* adr_complete,char* fil_complete,char* save,char* former_adr,char* former_fil,char* referer_adr,char* referer_fil,httrackp* opt,lien_url** liens,int lien_tot,lien_back* back,int back_max,cache_back* cache,hash_struct* hash,int ptr,int numero_passe) {
  85.   char newfil[HTS_URLMAXSIZE*2];   /* ="" */
  86.   /*char normadr_[HTS_URLMAXSIZE*2];*/
  87.   char normfil_[HTS_URLMAXSIZE*2];
  88.   char* normadr;
  89.   char* normfil;
  90.   char* fil;
  91.   char* adr;
  92.   char* print_adr;
  93.   char *start_pos=NULL,*nom_pos=NULL,*dot_pos=NULL;  // Position nom et point
  94.   // pour changement d'extension ou de nom (content-disposition)
  95.   int ext_chg=0;
  96.   char ext[256];
  97.   int max_char=0;
  98.   //CLEAR
  99.   newfil[0]=ext[0]='\0';
  100.  
  101.   /* 8-3 ? */
  102.   switch(opt->savename_83) {
  103.   case 1:
  104.     max_char=8;
  105.     break;
  106.   case 2:
  107.     max_char=30;
  108.     break;
  109.   default:
  110.     max_char=8;
  111.     break;
  112.   }
  113.  
  114.   // effacer save
  115.   save[0]='\0';
  116.   // fil
  117.   fil = fil_complete;
  118.   // copy of fil, used for lookups (see urlhack)
  119.   normfil = fil;
  120.   // et adr (sauter user/pass)
  121.   // on prend le parti de mettre les fichiers avec login/pass au mΩme endroit que si ils
  122.   // Θtaient capturΘs sans ces paramΦtres
  123.   // c'est pour cette raison qu'on ignore totalement adr_complete (mΩme pour la recherche en table de hachage)
  124.   adr = jump_identification(adr_complete);
  125.   // copy of adr, used for lookups (see urlhack)
  126.   normadr = adr;
  127.  
  128.   // normalize the URL:
  129.   // www.foo.com -> foo.com
  130.   // www-42.foo.com -> foo.com
  131.   // foo.com/bar//foobar -> foo.com/bar/foobar
  132.   if (opt->urlhack) {
  133.     // copy of adr (withiotu protocol), used for lookups (see urlhack)
  134.     normadr=jump_normalized(adr);
  135.     normfil=fil_normalized(fil,normfil_);
  136.   }
  137.  
  138.   // α afficher sans ftp://
  139.   print_adr=jump_protocol(adr);
  140.  
  141.   // court-circuit pour lien primaire
  142.   if (strnotempty(adr)==0) {
  143.     if (strcmp(fil,"primary")==0) {
  144.       strcatbuff(save,"primary.html");
  145.       return 0;
  146.     }
  147.   }
  148.  
  149.  
  150.   // vΘrifier que le nom n'a pas dΘja ΘtΘ calculΘ (si oui le renvoyer tel que)
  151.   // vΘrifier que le nom n'est pas dΘja pris...
  152.   // NOTE: si on cherche /toto/ et que /toto est trouvΘ on le prend (et rΘciproquqment) ** // **
  153.   if (liens!=NULL) { 
  154.     int i;
  155.  
  156. #if HTS_HASH
  157.     i=hash_read(hash,normadr,normfil,1,opt->urlhack);      // recherche table 1 (adr+fil)
  158.     if (i>=0) {    // ok, trouvΘ
  159.       strcpybuff(save,liens[i]->sav);
  160.       return 0;
  161.     }
  162.     i=hash_read(hash,normadr,normfil,2,opt->urlhack);      // recherche table 2 (former_adr+former_fil)
  163.     if (i>=0) {    // ok, trouvΘ
  164.       // copier location moved!
  165.       strcpybuff(adr_complete,liens[i]->adr);
  166.       strcpybuff(fil_complete,liens[i]->fil);
  167.       // et save
  168.       strcpybuff(save,liens[i]->sav);  // copier (formΘ α partir du nouveau lien!)
  169.       return 0;
  170.     }
  171. #else
  172.     for(i=lien_tot-1;i>=0;i--) {        
  173. #if HTS_CASSE
  174.       if ((strcmp(liens[i]->adr,normadr)==0) && (strcmp(liens[i]->fil,normfil)==0))
  175. #else
  176.       if ((strfield2(liens[i]->adr,normadr)) && (strfield2(liens[i]->fil,normfil)))
  177. #endif
  178.       {    // ok c'est le mΩme lien, adresse dΘja dΘfinie
  179.         strcpybuff(save,liens[i]->sav);
  180.         return 0;
  181.       }
  182.       if (liens[i]->former_adr) {     // tester ancienne loc?
  183. #if HTS_CASSE
  184.         if ((strcmp(liens[i]->former_adr,normadr)==0) && (strcmp(liens[i]->former_fil,normfil)==0))
  185. #else
  186.         if ((strfield2(liens[i]->former_adr,normadr)) && (strfield2(liens[i]->former_fil,normfil)))
  187. #endif
  188.         {
  189.           // copier location moved!
  190.           strcpybuff(adr_complete,liens[i]->adr);
  191.           strcpybuff(fil_complete,liens[i]->fil);
  192.           // et save
  193.           strcpybuff(save,liens[i]->sav);  // copier (formΘ α partir du nouveau lien!)
  194.           return 0;
  195.         }
  196.       }
  197.     }
  198. #endif
  199.  
  200.     // chercher sans / ou avec / dans former
  201.     {
  202.       char fil_complete_patche[HTS_URLMAXSIZE*2];
  203.       strcpybuff(fil_complete_patche,normfil);
  204.       // Version avec ou sans /
  205.       if (fil_complete_patche[strlen(fil_complete_patche)-1]=='/')
  206.         fil_complete_patche[strlen(fil_complete_patche)-1]='\0';
  207.       else
  208.         strcatbuff(fil_complete_patche,"/");
  209. #if HTS_HASH
  210.       i=hash_read(hash,normadr,fil_complete_patche,2,opt->urlhack);      // recherche table 2 (former_adr+former_fil)
  211.       if (i>=0) {
  212.         // Θcraser fil et adr (pas former_fil?????)
  213.         strcpybuff(adr_complete,liens[i]->adr);
  214.         strcpybuff(fil_complete,liens[i]->fil);
  215.         // Θcrire save
  216.         strcpybuff(save,liens[i]->sav);
  217.         return 0;
  218.       }
  219. #else
  220.       // mΩme boucle en gros
  221.       for(i=lien_tot-1;i>=0;i--) {        
  222.         if (liens[i]->former_adr) {    // former-adr?
  223. #if HTS_CASSE
  224.           if ((strcmp(liens[i]->former_adr,normadr)==0) && (strcmp(liens[i]->former_fil,fil_complete_patche)==0))
  225. #else
  226.           if ((strfield2(liens[i]->former_adr,normadr)) && (strfield2(liens[i]->former_fil,fil_complete_patche)))
  227. #endif
  228.           {    // ok c'est le mΩme lien, adresse dΘja dΘfinie
  229.             // Θcraser fil et adr (pas former_fil?????)
  230.             strcpybuff(adr_complete,liens[i]->adr);
  231.             strcpybuff(fil_complete,liens[i]->fil);
  232.             // Θcrire save
  233.             strcpybuff(save,liens[i]->sav);
  234.             return 0;
  235.           }
  236.         }
  237.       }
  238. #endif
  239.     }
  240.   }
  241.  
  242.   // vΘrifier la non prΘsence de paramΦtres dans le nom de fichier
  243.   // si il y en a, les supprimer (ex: truc.cgi?subj=aspirateur)
  244.   // nΘanmoins, gardΘ pour vΘrifier la non duplication (voir aprΦs)
  245.   {
  246.     char* a;
  247.     a=strchr(fil,'?');
  248.     if (a!=NULL) {
  249.       strncatbuff(newfil,fil,(int) (a - fil));
  250.     } else {
  251.       strcpybuff(newfil,fil);
  252.     }
  253.     fil=newfil;
  254.   }
  255.   // dΘcoder %
  256.   strcpybuff(fil,unescape_http(fil));
  257.   /*
  258.   {
  259.     char tempo[HTS_URLMAXSIZE*2];
  260.     int i,j=0;
  261.     for (i=0;i<(int) strlen(fil);i++) {
  262.       if (fil[i]=='%') {
  263.         i++;
  264.         tempo[j++]=(char) ehex(fil+i);
  265.         i++;    // sauter 2 caractΦres finalement
  266.       } else
  267.         tempo[j++]=fil[i];
  268.     }
  269.     tempo[j++]='\0';
  270.     strcpybuff(fil,tempo);
  271.   }
  272.   */
  273.   
  274.   
  275.   /* replace shtml to html.. */
  276.   switch (ishtml(fil)) {       /* .html,.shtml,.. */
  277.   case 1:
  278.     if ( 
  279.       (strcmp(get_ext(fil),"html") != 0)
  280.       && (strcmp(get_ext(fil),"htm") != 0)
  281.       ) {
  282.       strcpybuff(ext,"html");
  283.       ext_chg=1;
  284.     }
  285.     break;
  286.     case 0:
  287.       if (!strnotempty(ext)) {
  288.         if (is_userknowntype(get_ext(fil))) {      // mime known by user
  289.           char mime[1024];
  290.           mime[0]=ext[0]='\0';
  291.           get_userhttptype(0,mime,get_ext(fil));
  292.           if (strnotempty(mime)) {
  293.             give_mimext(ext,mime);
  294.             if (strnotempty(ext)) {
  295.               ext_chg=1;
  296.             }
  297.           }
  298.         }
  299.       }
  300.       break;
  301.   }
  302.   
  303.  
  304.   // si option check_type activΘe
  305.   if ((opt->check_type) && (!ext_chg)) {
  306.     int ishtest;
  307.     if ( (!strfield(adr_complete,"file://")) 
  308.       && (!strfield(adr_complete,"ftp://")) 
  309.       ) {
  310.       // tester type avec requΦte HEAD si on ne connait pas le type du fichier
  311.       if (!(   (opt->check_type==1) && (fil[strlen(fil)-1]=='/')   ))    // slash doit Ωtre html?
  312.       if ((ishtest=ishtml(fil)) < 0) { // on ne sait pas si c'est un html ou un fichier..
  313.         // lire dans le cache
  314.         htsblk r = cache_read(opt,cache,adr,fil,NULL,NULL);              // test uniquement
  315.         if (r.statuscode != -1) {  // pas d'erreur de lecture cache
  316.           char s[16]; s[0]='\0';
  317.           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  318.             fspc(opt->log,"debug"); fprintf(opt->log,"Testing link type (from cache) %s%s"LF,adr_complete,fil_complete);
  319.             test_flush;
  320.           }
  321.           if (strnotempty(r.cdispo)) {        /* filename given */
  322.             ext_chg=2;      /* change filename */
  323.             strcpybuff(ext,r.cdispo);
  324.           }
  325.           else if (!may_unknown(r.contenttype) || ishtest == -2) {  // on peut patcher α priori?
  326.             give_mimext(s,r.contenttype);  // obtenir extension
  327.             if (strnotempty(s)>0) {        // on a reconnu l'extension
  328.               ext_chg=1;
  329.               strcpybuff(ext,s);
  330.             }
  331.           }
  332.           //
  333.         } else {          // test imposible dans le cache, faire une requΩte
  334.           //
  335. #if HTS_ANALYSTE
  336.           int hihp=_hts_in_html_parsing;
  337. #endif
  338.           int has_been_moved=0;
  339.           char curr_adr[HTS_URLMAXSIZE*2],curr_fil[HTS_URLMAXSIZE*2];
  340.           curr_adr[0]=curr_fil[0]='\0';
  341. #if HTS_ANALYSTE
  342.           _hts_in_html_parsing=2;  // test
  343. #endif
  344.           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  345.             fspc(opt->log,"debug"); fprintf(opt->log,"Testing link type %s%s"LF,adr_complete,fil_complete);
  346.             test_flush;
  347.           }
  348.           strcpybuff(curr_adr,adr_complete);
  349.           strcpybuff(curr_fil,fil_complete);
  350.           // ajouter dans le backing le fichier en mode test
  351.           // savename: rien car en mode test
  352.           if (back_add(back,back_max,opt,cache,curr_adr,curr_fil,BACK_ADD_TEST,referer_adr,referer_fil,1,NULL)!=-1) {
  353.             int b;
  354.             b=back_index(back,back_max,curr_adr,curr_fil,BACK_ADD_TEST);         
  355.             if (b>=0) {
  356.               int stop_looping=0;
  357.               int petits_tours=0;
  358.               int get_test_request=0;       // en cas de bouclage sur soi mΩme avec HEAD, tester avec GET.. parfois c'est la cause des problΦmes
  359.               do {
  360.                 // temps α attendre, et remplir autant que l'on peut le cache (backing)
  361.                 if (back[b].status>0) {
  362.                   back_wait(back,back_max,opt,cache,0);        
  363.                 }
  364.                 if (ptr>=0) {
  365.                   back_fillmax(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
  366.                 }
  367.   
  368.                 // on est obligΘ d'appeler le shell pour le refresh..
  369. #if HTS_ANALYSTE
  370.                 {
  371.                   
  372.                   // Transfer rate
  373.                   engine_stats();
  374.                   
  375.                   // Refresh various stats
  376.                   HTS_STAT.stat_nsocket=back_nsoc(back,back_max);
  377.                   HTS_STAT.stat_errors=fspc(NULL,"error");
  378.                   HTS_STAT.stat_warnings=fspc(NULL,"warning");
  379.                   HTS_STAT.stat_infos=fspc(NULL,"info");
  380.                   HTS_STAT.nbk=backlinks_done(liens,lien_tot,ptr);
  381.                   HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
  382.  
  383.                   if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) {
  384.                     return -1;
  385.                   } else if (_hts_cancel || !back_checkmirror(opt)) {    // cancel 2 ou 1 (cancel parsing)
  386.                     back_delete(opt,back,b);       // cancel test
  387.                     stop_looping = 1;
  388.                   }
  389.                 }
  390. #endif
  391.                 
  392.                 
  393.                 // traitement des 304,303..
  394.                 if (back[b].status<=0) {
  395.                   if (    (back[b].r.statuscode==301)
  396.                        || (back[b].r.statuscode==302)
  397.                        || (back[b].r.statuscode==303)
  398.                        || (back[b].r.statuscode==307)
  399.                      ) {    // agh moved.. un tit tour de plus
  400.                     if ((petits_tours<5) && (former_adr) && (former_fil)) { // on va pas tourner en rond non plus!
  401.                       if ((int) strnotempty(back[b].r.location)) {    // location existe!
  402.                         char mov_url[HTS_URLMAXSIZE*2],mov_adr[HTS_URLMAXSIZE*2],mov_fil[HTS_URLMAXSIZE*2];
  403.                         mov_url[0]=mov_adr[0]=mov_fil[0]='\0';
  404.                         //
  405.                         strcpybuff(mov_url,back[b].r.location);    // copier URL
  406.                         if (ident_url_relatif(mov_url,curr_adr,curr_fil,mov_adr,mov_fil)>=0) {                        
  407.                           // si non bouclage sur soi mΩme, ou si test avec GET non testΘ
  408.                           if ((strcmp(mov_adr,curr_adr)) || (strcmp(mov_fil,curr_fil)) || (get_test_request==0)) {
  409.                             // bouclage?
  410.                             if ((!strcmp(mov_adr,curr_adr)) && (!strcmp(mov_fil,curr_fil)))
  411.                               get_test_request=1;     // faire requΦte avec GET
  412.  
  413.                             // recopier former_adr/fil?
  414.                             if ((former_adr) && (former_fil)) {
  415.                               if (strnotempty(former_adr)==0) {    // Pas dΘja notΘ
  416.                                 strcpybuff(former_adr,curr_adr);
  417.                                 strcpybuff(former_fil,curr_fil);
  418.                               }
  419.                             }
  420.  
  421.                             // check explicit forbidden - don't follow 3xx in this case
  422.                             {
  423.                               int set_prio_to=0;
  424.                               robots_wizard* robots = (robots_wizard*) opt->robotsptr;
  425.                               if (hts_acceptlink(opt,ptr,lien_tot,liens,
  426.                                 mov_adr,mov_fil,
  427.                                 &set_prio_to,
  428.                                 NULL) == 1) 
  429.                               {  /* forbidden */
  430.                                 has_been_moved = 1;
  431.                                 back_maydelete(opt,back,b);    // ok
  432.                                 strcpybuff(curr_adr,mov_adr);
  433.                                 strcpybuff(curr_fil,mov_fil);
  434.                                 mov_url[0]='\0';
  435.                                 stop_looping = 1;
  436.                               }
  437.                             }
  438.                             
  439.                             // ftp: stop!
  440.                             if (strfield(mov_url,"ftp://")) {    // ftp, ok on arrΩte
  441.                               has_been_moved = 1;
  442.                               back_maydelete(opt,back,b);    // ok
  443.                               strcpybuff(curr_adr,mov_adr);
  444.                               strcpybuff(curr_fil,mov_fil);
  445.                               stop_looping = 1;
  446.                             } else if (*mov_url) {
  447.                               char* methode;
  448.                               if (!get_test_request)
  449.                                 methode=BACK_ADD_TEST;      // tester avec HEAD
  450.                               else {
  451.                                 methode=BACK_ADD_TEST2;     // tester avec GET
  452.                                 if ( opt->errlog!=NULL ) {
  453.                                   fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Loop with HEAD request (during prefetch) at %s%s"LF,curr_adr,curr_fil);
  454.                                   test_flush;
  455.                                 }                    
  456.                               }
  457.                               // Ajouter
  458.                               if (back_add(back,back_max,opt,cache,mov_adr,mov_fil,methode,referer_adr,referer_fil,1,NULL)!=-1) {    // OK
  459.                                 if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  460.                                   fspc(opt->errlog,"warning"); fprintf(opt->errlog,"(during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil);
  461.                                   test_flush;
  462.                                 }
  463.                                 
  464.                                 // libΘrer emplacement backing actuel et attendre le prochain
  465.                                 back_maydelete(opt,back,b);
  466.                                 strcpybuff(curr_adr,mov_adr);
  467.                                 strcpybuff(curr_fil,mov_fil);
  468.                                 b=back_index(back,back_max,curr_adr,curr_fil,methode);         
  469.                                 if (!get_test_request)
  470.                                   has_been_moved = 1;       // sinon ne pas forcer has_been_moved car non dΘplacΘ
  471.                                 petits_tours++;
  472.                                 //
  473.                               } else {// sinon on fait rien et on s'en va.. (ftp etc)
  474.                                 if ( (opt->debug>1)  && (opt->errlog)) {
  475.                                   fspc(opt->errlog,"debug"); fprintf(opt->errlog,"Warning: Savename redirect backing error at %s%s"LF,mov_adr,mov_fil);
  476.                                   test_flush;
  477.                                 } 
  478.                               }
  479.                             }
  480.                           } else {
  481.                             if ( opt->errlog!=NULL ) {
  482.                               fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Unable to test %s%s (loop to same filename)"LF,adr_complete,fil_complete);
  483.                               test_flush;
  484.                             }
  485.                           }
  486.                           
  487.                         }
  488.                       }
  489.                     } else{  // arrΩter les frais
  490.                       if ( opt->errlog!=NULL ) {
  491.                         fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Unable to test %s%s (loop)"LF,adr_complete,fil_complete);
  492.                         test_flush;
  493.                       }
  494.                     }
  495.                   }  // ok, leaving
  496.                 }
  497.               } while(!stop_looping && back[b].status > 0 && back[b].status < 1000);
  498.               
  499.               // Si non dΘplacΘ, forcer type?
  500.               if (!has_been_moved) {
  501.                 if (back[b].r.statuscode!=-10) {    // erreur
  502.                   if (strnotempty(back[b].r.contenttype)==0)
  503.                     strcpybuff(back[b].r.contenttype,"text/html");    // message d'erreur en html
  504.                   // Finalement on, renvoie un erreur, pour ne toucher α rien dans le code
  505.                   // libΘrer emplacement backing
  506.                   /*if (opt->errlog!=NULL) {
  507.                     fspc(opt->errlog,0); fprintf(opt->errlog,"Error: (during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil);
  508.                     test_flush;
  509.                   }                    
  510.                   back_delete(opt,back,b);
  511.                   return -1;        // ERREUR (404 par exemple)
  512.                   */
  513.                 } 
  514.                 
  515.                 {            // pas d'erreur, changer type?
  516.                   char s[16];
  517.                   s[0]='\0';
  518.                   if (strnotempty(back[b].r.cdispo)) {        /* filename given */
  519.                     ext_chg=2;      /* change filename */
  520.                     strcpybuff(ext,back[b].r.cdispo);
  521.                   }
  522.                   else if (!may_unknown(back[b].r.contenttype) || ishtest == -2 ) {  // on peut patcher α priori? (pas interdit ou pas de type)
  523.                     give_mimext(s,back[b].r.contenttype);  // obtenir extension
  524.                     if (strnotempty(s)>0) {    // on a reconnu l'extension
  525.                       ext_chg=1;
  526.                       strcpybuff(ext,s);
  527.                     }
  528.                   }
  529.                 }
  530.               }
  531.               // FIN Si non dΘplacΘ, forcer type?
  532.  
  533.               // libΘrer emplacement backing
  534.               back_maydelete(opt,back,b);
  535.               
  536.               // --- --- ---
  537.               // oops, a ΘtΘ dΘplacΘ.. on recalcule en rΘcursif (osons!)
  538.               if (has_been_moved) {
  539.                 // copier adr, fil (optionnel, mais sinon marche pas pour le rip)
  540.                 strcpybuff(adr_complete,curr_adr);
  541.                 strcpybuff(fil_complete,curr_fil);
  542.                 // copier adr, fil
  543.                 
  544.                 return url_savename(curr_adr,curr_fil,save,NULL,NULL,referer_adr,referer_fil,opt,liens,lien_tot,back,back_max,cache,hash,ptr,numero_passe);
  545.               }
  546.               // --- --- ---
  547.               
  548.             }
  549.             
  550.           } else {
  551.             printf("PANIC! : Savename Crash adding error, unexpected error found.. [%d]\n",__LINE__);
  552. #if BDEBUG==1
  553.             printf("error while savename crash adding\n");
  554. #endif
  555.             if (opt->errlog) {
  556.               fspc(opt->errlog,"error"); fprintf(opt->errlog,"Unexpected savename backing error at %s%s"LF,adr,fil_complete);
  557.               test_flush;
  558.             } 
  559.             
  560.           }
  561.           // restaurer
  562. #if HTS_ANALYSTE
  563.           _hts_in_html_parsing=hihp;
  564. #endif
  565.         }  // cachΘ?
  566.       }
  567.     }
  568.   }
  569.  
  570.  
  571.  
  572.   // - - - DEBUT NOMMAGE - - -
  573.  
  574.   // Donner nom par dΘfaut?
  575.   if (fil[strlen(fil)-1]=='/')  {
  576.     if (!strfield(adr_complete,"ftp://"))
  577.       strcatbuff(fil,DEFAULT_HTML);     // nommer page par dΘfaut!!
  578.     else {
  579.       if (!opt->proxy.active)
  580.         strcatbuff(fil,DEFAULT_FTP);     // nommer page par dΘfaut (texte)
  581.       else
  582.         strcatbuff(fil,DEFAULT_HTML);     // nommer page par dΘfaut (α priori ici html depuis un proxy http)
  583.     }
  584.   }
  585.   // Changer extension?
  586.   // par exemple, php3 sera sauvΘ en html, cgi en html ou gif, xbm etc.. selon les cas
  587.   if (ext_chg) {  // changer ext
  588.     char* a=fil+strlen(fil)-1;
  589.     if ( (opt->debug>1) && (opt->log!=NULL) ) {
  590.       fspc(opt->log,"debug");
  591.       if (ext_chg==1)
  592.         fprintf(opt->log,"Changing link extension %s%s to .%s"LF,adr_complete,fil_complete,ext);
  593.       else
  594.         fprintf(opt->log,"Changing link name %s%s to %s"LF,adr_complete,fil_complete,ext);
  595.       test_flush;
  596.     }
  597.     if (ext_chg==1) {
  598.       while((a > fil) && (*a!='.') && (*a!='/')) a--;
  599.       if (*a=='.') *a='\0';  // couper
  600.       strcatbuff(fil,".");      // recopier point
  601.     } else {
  602.       while(( a > fil) && (*a!='/')) a--;
  603.       if (*a=='/') a++;
  604.       *a='\0';
  605.    }
  606.     strcatbuff(fil,ext);    // copier ext/nom
  607.   }
  608.  
  609.   // Rechercher premier / et dernier .
  610.   {  
  611.     char* a=fil+strlen(fil)-1;
  612.  
  613.     // passer structures
  614.     start_pos=fil;
  615.     while(( a > fil) && (*a != '/') && (*a != '\\')) {
  616.       if (*a == '.')    // point? noter position
  617.         if (!dot_pos)
  618.           dot_pos=a;
  619.         a--;
  620.     }
  621.     if ((*a=='/') || (*a=='\\')) a++;
  622.     nom_pos = a;
  623.   }
  624.  
  625.   
  626.   // un nom de fichier est gΘnΘrΘ
  627.   // s'il existe dΘja, alors on le mofifie lΘgΦrement
  628.  
  629.   // ajouter nom du site Θventuellement en premier
  630.   if (opt->savename_type == -1) {    // utiliser savename_userdef! (%h%p/%n%q.%t)
  631.     char* a = opt->savename_userdef;
  632.     char* b = save;
  633.     /*char *nom_pos=NULL,*dot_pos=NULL;  // Position nom et point */
  634.     char tok;
  635.  
  636.     /*
  637.     {  // Rechercher premier /
  638.       char* a=fil+strlen(fil)-1;
  639.       // passer structures
  640.       while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) {
  641.         if (*a == '.')    // point? noter position
  642.         if (!dot_pos)
  643.           dot_pos=a;
  644.         a--;
  645.       }
  646.       if ((*a=='/') || (*a=='\\')) a++;
  647.       nom_pos = a;
  648.     }
  649.     */
  650.  
  651.     // Construire nom
  652.     while ((*a) && (((int) (b - save)) < HTS_URLMAXSIZE ) ) {    // parser, et pas trop long..
  653.       if (*a == '%') {
  654.         int short_ver=0;
  655.         a++;
  656.         if (*a == 's') {
  657.           short_ver=1;
  658.           a++;
  659.         }
  660.         *b='\0';
  661.         switch(tok=*a++) {
  662.           case '[':            // %[param:prefix_if_not_empty:suffix_if_not_empty:empty_replacement:notfound_replacement]
  663.             if (strchr(a,']')) {
  664.               int pos=0;
  665.               char name[5][256];
  666.               char* c=name[0];
  667.               for(pos = 0 ; pos < 5 ; pos++) {
  668.                 name[pos][0]='\0';
  669.               }
  670.               pos=0;
  671.               while(*a!=']') {
  672.                 if (pos < 5) {
  673.                   if (*a == ':') {  // next token
  674.                     c=name[++pos];
  675.                     a++;
  676.                   } else {
  677.                     *c++=*a++;
  678.                     *c='\0';
  679.                   }
  680.                 }
  681.               }
  682.               a++;
  683.               strcatbuff(name[0],"=");           /* param=.. */
  684.               c=strchr(fil_complete,'?');
  685.               /* parameters exists */
  686.               if (c) {
  687.                 char* cp;
  688.                 while((cp = strstr(c+1, name[0])) && *(cp-1) != '?' && *(cp-1) != '&') {     /* finds [?&]param= */
  689.                   c = cp;
  690.                 }
  691.                 if (cp) {
  692.                   c = cp + strlen(name[0]);    /* jumps "param=" */
  693.                   strcpybuff(b, name[1]);    /* prefix */
  694.                   b += strlen(b);
  695.                   if (*c != '\0' && *c != '&') {
  696.                     char* d = name[0];
  697.                     /* */
  698.                     while(*c != '\0' && *c != '&') {
  699.                       *d++ = *c++;
  700.                     }
  701.                     *d = '\0';
  702.                     d = unescape_http(name[0]);
  703.                     if (d && *d) {
  704.                       strcpybuff(b, d);         /* value */
  705.                       b += strlen(b);
  706.                     } else {
  707.                       strcpybuff(b, name[3]);    /* empty replacement if any */
  708.                       b += strlen(b);
  709.                     }
  710.                   } else {
  711.                     strcpybuff(b, name[3]);    /* empty replacement if any */
  712.                     b += strlen(b);
  713.                   }
  714.                   strcpybuff(b, name[2]);    /* suffix */
  715.                   b += strlen(b);
  716.                 } else {
  717.                   strcpybuff(b, name[4]);    /* not found replacement if any */
  718.                   b += strlen(b);
  719.                 }
  720.               }
  721.             }
  722.           break;
  723.           case '%': *b++='%'; break;
  724.           case 'n':    // nom sans ext
  725.             if (dot_pos) {
  726.               if (!short_ver)    // Noms longs
  727.                 strncatbuff(b,nom_pos,(int) (dot_pos - nom_pos));
  728.               else
  729.                 strncatbuff(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  730.             } else {
  731.               if (!short_ver)    // Noms longs
  732.                 strcpybuff(b,nom_pos);
  733.               else
  734.                 strncatbuff(b,nom_pos,8);
  735.             }
  736.             b+=strlen(b);   // pointer α la fin
  737.             break;
  738.           case 'N':    // nom avec ext
  739.             // RECOPIE NOM + EXT
  740.             *b='\0';
  741.             if (dot_pos) {
  742.               if (!short_ver)    // Noms longs
  743.                 strncatbuff(b,nom_pos,(int) (dot_pos - nom_pos));
  744.               else
  745.                 strncatbuff(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  746.             } else {
  747.               if (!short_ver)    // Noms longs
  748.                 strcpybuff(b,nom_pos);
  749.               else
  750.                 strncatbuff(b,nom_pos,8);
  751.             }
  752.             b+=strlen(b);   // pointer α la fin
  753.             // RECOPIE NOM + EXT
  754.             *b='\0';
  755.             if (dot_pos) {
  756.               if (!short_ver)    // Noms longs
  757.                 strcpybuff(b,dot_pos+1);
  758.               else
  759.                 strncatbuff(b,dot_pos+1,3);
  760.             } else {
  761.               if (!short_ver)    // Noms longs
  762.                 strcpybuff(b,DEFAULT_EXT);    // pas de..
  763.               else
  764.                 strcpybuff(b,DEFAULT_EXT_SHORT);    // pas de..
  765.             }
  766.             b+=strlen(b);   // pointer α la fin
  767.             //
  768.             break;
  769.           case 't':    // ext
  770.             *b='\0';
  771.             if (dot_pos) {
  772.               if (!short_ver)    // Noms longs
  773.                 strcpybuff(b,dot_pos+1);
  774.               else
  775.                 strncatbuff(b,dot_pos+1,3);
  776.             } else {
  777.               if (!short_ver)    // Noms longs
  778.                 strcpybuff(b,DEFAULT_EXT);    // pas de..
  779.               else
  780.                 strcpybuff(b,DEFAULT_EXT_SHORT);    // pas de..
  781.             }
  782.             b+=strlen(b);   // pointer α la fin
  783.             break;
  784.           case 'p':    // path sans dernier /
  785.             *b='\0';
  786.             if (nom_pos != fil + 1) { // pas: /index.html (chemin nul)
  787.               if (!short_ver) {   // Noms longs
  788.                 strncatbuff(b,fil,(int) (nom_pos - fil) - 1);
  789.               } else {
  790.                 char pth[HTS_URLMAXSIZE*2],n83[HTS_URLMAXSIZE*2];
  791.                 pth[0]=n83[0]='\0';
  792.                 //
  793.                 strncatbuff(pth,fil,(int) (nom_pos - fil) - 1);
  794.                 long_to_83(opt->savename_83,n83,pth);
  795.                 strcpybuff(b,n83);
  796.               }
  797.             }
  798.             b+=strlen(b);   // pointer α la fin
  799.             break;
  800.           case 'h':    // host
  801.             *b='\0';
  802.             if (strcmp(adr_complete,"file://")==0) {
  803.               if (!short_ver)    // Noms longs
  804.                 strcpybuff(b,"localhost");
  805.               else
  806.                 strcpybuff(b,"local");
  807.             } else {
  808.               if (!short_ver)    // Noms longs
  809.                 strcpybuff(b,print_adr);
  810.               else
  811.                 strncatbuff(b,print_adr,8);
  812.             }
  813.             b+=strlen(b);   // pointer α la fin
  814.             break;
  815.           case 'M':         /* host/address?query MD5 (128-bits) */
  816.             *b='\0';
  817.             {
  818.               char digest[32+2];
  819.               char buff[HTS_URLMAXSIZE*2];
  820.               digest[0]=buff[0]='\0';
  821.               strcpybuff(buff,adr);
  822.               strcatbuff(buff,fil_complete);
  823.               domd5mem(buff,strlen(buff),digest,1);
  824.               strcpybuff(b,digest);
  825.             }
  826.             b+=strlen(b);   // pointer α la fin
  827.             break;
  828.           case 'Q': case 'q':         /* query MD5 (128-bits/16-bits) 
  829.                                          GENERATED ONLY IF query string exists! */
  830.             *b='\0';
  831.             strncatbuff(b,url_md5(fil_complete),(tok == 'Q')?32:4);
  832.             b+=strlen(b);   // pointer α la fin
  833.             break;
  834.         }
  835.       } else
  836.         *b++=*a++;
  837.     }
  838.     *b++='\0';
  839.     //
  840.     // Types prΘdΘfinis
  841.     //
  842.  
  843.   } 
  844.   //
  845.   // Structure originale
  846.   else if (opt->savename_type%100==0) { 
  847.     /* recopier www.. */
  848.     if (opt->savename_type!=100) {  
  849.       if (((opt->savename_type/1000)%2)==0) {    // >1000 signifie "pas de www/"
  850.         if (strcmp(adr_complete,"file://")==0) {
  851.           //## if (*adr==lOCAL_CHAR) {
  852.           if (opt->savename_83 != 1)  // noms longs
  853.             strcatbuff(save,"localhost");
  854.           else
  855.             strcatbuff(save,"local");
  856.         } else {
  857.           // adresse url
  858.           if (!opt->savename_83) {  // noms longs (et pas de .)
  859.             strcatbuff(save,print_adr);
  860.           } else {  // noms 8-3
  861.             if (strlen(print_adr)>4) {
  862.               if (strfield(print_adr,"www."))
  863.                 strncatbuff(save,print_adr+4,max_char);
  864.               else
  865.                 strncatbuff(save,print_adr,8);
  866.             } else strncatbuff(save,print_adr,max_char);
  867.           }
  868.         }
  869.         if (*fil!='/') strcatbuff(save,"/");
  870.       }
  871.     }
  872.   
  873. #if HTS_CASSE==0
  874.     hts_lowcase(save);
  875. #endif  
  876.         
  877.     /*
  878.     // ne sert α rien car a dΘja ΘtΘ filtrΘ normalement
  879.     if ((*fil=='.') && (*(fil+1)=='/'))          // ./index.html ** //
  880.       url_savename_addstr(save,fil+2);
  881.     else                                               // index.html ou /index.html
  882.       url_savename_addstr(save,fil);
  883.     if (save[strlen(save)-1]=='/') 
  884.       strcatbuff(save,DEFAULT_HTML);     // nommer page par dΘfaut!!
  885. */
  886.  
  887.     /* add name */
  888.     ADD_STANDARD_PATH;
  889.     ADD_STANDARD_NAME(0);
  890.  
  891.   }
  892.   //
  893.   // Structure html/image
  894.   else {    
  895.     // dossier "web" ou "www.xxx" ?
  896.     if (((opt->savename_type/1000)%2)==0) {    // >1000 signifie "pas de www/"
  897.       if ((opt->savename_type/100)%2) {
  898.         if (strcmp(adr_complete,"file://")==0) {
  899.         //## if (*adr==lOCAL_CHAR) {
  900.           if (opt->savename_83 != 1)  // noms longs
  901.             strcatbuff(save,"localhost/");
  902.           else
  903.             strcatbuff(save,"local/");
  904.         } else {
  905.           // adresse url
  906.           if (!opt->savename_83) {  // noms longs
  907.             strcatbuff(save,print_adr); strcatbuff(save,"/");
  908.           } else {  // noms 8-3
  909.             if (strlen(print_adr)>4) {
  910.               if (strfield(print_adr,"www."))
  911.                 strncatbuff(save,print_adr+4,max_char);
  912.               else
  913.                 strncatbuff(save,print_adr,max_char);
  914.               strcatbuff(save,"/");
  915.             } else { 
  916.               strncatbuff(save,print_adr,max_char); strcatbuff(save,"/");
  917.             }
  918.           }
  919.         }
  920.       } else {
  921.         strcatbuff(save,"web/");    // rΘpertoire gΘnΘral
  922.       }
  923.     } 
  924.  
  925.     // si un html α coup s√r
  926.     if ( (ext_chg!=0) ? (ishtml_ext(ext)==1) : (ishtml(fil)==1) ) {
  927.       if (opt->savename_type%100==2) {  // html/
  928.         strcatbuff(save,"html/");
  929.       }
  930.     } else {
  931.       if ((opt->savename_type%100==1) || (opt->savename_type%100==2)) {  // html & images
  932.         strcatbuff(save,"images/");
  933.       }
  934.     }
  935.     
  936.     switch (opt->savename_type%100) {
  937.     case 4: case 5: {           // sΘparer par types
  938.       char* a=fil+strlen(fil)-1;
  939.       // passer structures
  940.       while(( a > fil) && (*a != '/') && (*a != '\\')) a--;      
  941.       if ((*a=='/') || (*a=='\\')) a++;
  942.  
  943.       // html?
  944.       if ( (ext_chg!=0) ? (ishtml_ext(ext)==1) : (ishtml(fil)==1) ) {
  945.         if (opt->savename_type%100==5)
  946.           strcatbuff(save,"html/");
  947.       } else {
  948.         char* a=fil+strlen(fil)-1;
  949.         while(( a> fil) && (*a != '/') && (*a != '.')) a--;      
  950.         if (*a!='.')
  951.           strcatbuff(save,"other");
  952.         else
  953.           strcatbuff(save,a+1);
  954.         strcatbuff(save,"/");
  955.       }
  956.       /*strcatbuff(save,a);*/
  957.       /* add name */
  958.       ADD_STANDARD_NAME(0);
  959.             }
  960.       break;
  961.     case 99: {                  // 'codΘ' .. c'est un gadget
  962.       int i;
  963.       int j;
  964.       char* a;
  965.       char C[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
  966.       int L;
  967.       // pseudo-CRC sur fil et adr pour initialiser gΘnΘrateur alΘatoire..
  968.       unsigned int s=0;
  969.       L=strlen(C);
  970.       for(i=0;i<(int) strlen(fil_complete);i++) {
  971.         s+=(unsigned int) fil_complete[i];
  972.       }
  973.       for(i=0;i<(int) strlen(adr_complete);i++) {
  974.         s+=(unsigned int) adr_complete[i];
  975.       }
  976.       srand(s);
  977.       
  978.       j=strlen(save);
  979.       for(i=0;i<8;i++) {
  980.         char c=C[(rand()%L)];
  981.         save[i+j]=c;
  982.       }
  983.       save[i+j]='\0';
  984.       // ajouter extension
  985.       a=fil+strlen(fil)-1;
  986.       while(( a > fil) && (*a != '/') && (*a != '.')) a--;
  987.       if (*a=='.') {
  988.         strcatbuff(save,a);    // ajouter
  989.       }
  990.              } 
  991.       break;
  992.     default: {   // noms sans les noms des rΘpertoires
  993.       // ne garder que le nom, pas la structure
  994.       /*
  995.       char* a=fil+strlen(fil)-1;
  996.       while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) a--;      
  997.       if ((*a=='/') || (*a=='\\')) a++;
  998.       strcatbuff(save,a);
  999.       */
  1000.  
  1001.       /* add name */
  1002.       ADD_STANDARD_NAME(0);
  1003.             }
  1004.       break;
  1005.     }
  1006.  
  1007. #if HTS_CASSE==0
  1008.     hts_lowcase(save);
  1009. #endif  
  1010.  
  1011.     if (save[strlen(save)-1]=='/') 
  1012.       strcatbuff(save,DEFAULT_HTML);     // nommer page par dΘfaut!!
  1013.   }
  1014.  
  1015.  
  1016.   // vΘrifier qu'on ne doit pas forcer l'extension
  1017.   // par exemple, asp sera sauvΘ en html, cgi en html ou gif, xbm etc.. selon les cas
  1018.   /*if (ext_chg) {
  1019.     char* a=save+strlen(save)-1;
  1020.     while(((int) a>(int) save) && (*a!='.') && (*a!='/')) a--;
  1021.     if (*a=='.') *a='\0';  // couper
  1022.     // recopier extension
  1023.     strcatbuff(save,".");
  1024.     strcatbuff(save,ext);    // copier ext
  1025.   }*/
  1026.   // de mΩme en cas de manque d'extension on en place une de maniΦre forcΘe..
  1027.   // cela Θvite les /chez/toto et les /chez/toto/index.html incompatibles
  1028.   if (opt->savename_type != -1) {
  1029.     char* a=save+strlen(save)-1;
  1030.     while(( a > save) && (*a!='.') && (*a!='/')) a--;
  1031.     if (*a!='.') {   // agh pas de point
  1032.       //strcatbuff(save,".none");                 // a Θviter
  1033.       strcatbuff(save,".html");                   // prΘfΘrable!
  1034.       if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  1035.         fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Default HTML type set for %s%s"LF,adr_complete,fil_complete);
  1036.         test_flush;
  1037.       }
  1038.     }
  1039.   }
  1040.  
  1041.   // effacer pass au besoin pour les autentifications
  1042.   // (plus la peine : masquΘ au dΘbut)
  1043. /*
  1044.   {
  1045.     char* a=jump_identification(save);
  1046.     if (a!=save) {
  1047.       char tempo[HTS_URLMAXSIZE*2];
  1048.       char *b;
  1049.       tempo[0]='\0';
  1050.       strcpybuff(tempo,"[");
  1051.       b=strchr(save,':');
  1052.       if (!b) b=strchr(save,'@');
  1053.       if (b)
  1054.         strncatbuff(tempo,save,(int) b-(int) a);
  1055.       strcatbuff(tempo,"]");
  1056.       strcatbuff(tempo,a);
  1057.       strcpybuff(save,a);
  1058.     }
  1059.   }
  1060. */
  1061.  
  1062.   // Θviter les / au dΘbut (cause: N100)
  1063.   if (save[0]=='/') {
  1064.     char tempo[HTS_URLMAXSIZE*2];
  1065.     strcpybuff(tempo,save+1);
  1066.     strcpybuff(save,tempo);
  1067.   }
  1068.  
  1069.   // changer les ~,:,",*,? en _ pour sauver sur disque
  1070.   hts_replace(save,'~','_');  // interdit sous unix (~foo)
  1071.   //
  1072.   hts_replace(save,'\\','_');
  1073.   hts_replace(save,':','_');  // interdit sous windows
  1074.   hts_replace(save,'*','_');  // interdit sous windows
  1075.   hts_replace(save,'?','_');  // doit pas arriver!!
  1076.   hts_replace(save,'\"','_');  // interdit sous windows
  1077.   hts_replace(save,'<','_');  // interdit sous windows
  1078.   hts_replace(save,'>','_');  // interdit sous windows
  1079.   hts_replace(save,'|','_');  // interdit sous windows
  1080.   //
  1081.   hts_replace(save,'@','_');
  1082.   if (opt->savename_83 == 2) { // CDROM
  1083.     // maybe other ones?
  1084.     hts_replace(save,'-','_');
  1085.     hts_replace(save,'=','_');
  1086.     hts_replace(save,'+','_');
  1087.   }
  1088.   //
  1089.   { // Θliminer les // (comme ftp://)
  1090.     char* a;
  1091.     while( (a=strstr(save,"//")) ) *a='_';
  1092.     // Eliminer chars spΘciaux
  1093.     a=save -1 ;
  1094.     while(*(++a))
  1095.       if ( ((unsigned char)(*a) <= 31)
  1096.           || ((unsigned char)(*a) == 127) )
  1097.         *a='_';
  1098.   }
  1099.  
  1100.    
  1101. #if HTS_OVERRIDE_DOS_FOLDERS
  1102.   /* Replace /foo/nul/bar by /foo/nul_/bar */
  1103.   {
  1104.     int i=0;
  1105.     while(hts_tbdev[i][0]) {
  1106.       char* a=save;
  1107.       while((a=strstrcase(a,(char*)hts_tbdev[i]))) {
  1108.         switch ( (int) a[strlen(hts_tbdev[i])] ) {
  1109.         case '\0':
  1110.         case '/':
  1111.         case '.': 
  1112.         {
  1113.           char tempo[HTS_URLMAXSIZE*2]; tempo[0]='\0';
  1114.           strncatbuff(tempo,save,(int) (a - save) + strlen(hts_tbdev[i]));
  1115.           strcatbuff(tempo,"_");
  1116.           strcatbuff(tempo,a+strlen(hts_tbdev[i]));
  1117.           strcpybuff(save,tempo);
  1118.                    }
  1119.           break;
  1120.         }
  1121.         a+=strlen(hts_tbdev[i]);
  1122.       }
  1123.       i++;
  1124.     }
  1125.   }
  1126. #endif
  1127.  
  1128.   // conversion 8-3 .. y compris pour les rΘpertoires
  1129.   if (opt->savename_83) {
  1130.     char n83[HTS_URLMAXSIZE*2];
  1131.     long_to_83(opt->savename_83,n83,save);
  1132.     strcpybuff(save,n83);
  1133.   }
  1134.  
  1135.  
  1136.   /* ensure that there is no ../ (potential vulnerability) */
  1137.   fil_simplifie(save);
  1138.  
  1139. #if HTS_ANALYSTE
  1140.   {
  1141.     hts_htmlcheck_savename(adr_complete,fil_complete,referer_adr,referer_fil,save);
  1142.     if ( (opt->debug>0) && (opt->log!=NULL) ) {
  1143.       fspc(opt->log,"info"); fprintf(opt->log,"engine: save-name: local name: %s%s -> %s"LF,adr,fil,save);
  1144.       test_flush;
  1145.     }
  1146.   }
  1147. #endif
  1148.  
  1149.   // chemin primaire Θventuel A METTRE AVANT
  1150.   if (strnotempty(opt->path_html)) {
  1151.     char tempo[HTS_URLMAXSIZE*2];
  1152.     strcpybuff(tempo,opt->path_html);
  1153.     strcatbuff(tempo,save);
  1154.     strcpybuff(save,tempo);
  1155.   }
  1156.  
  1157.  
  1158.   // vΘrifier que le nom n'est pas dΘja pris...
  1159.   if (liens!=NULL) { 
  1160.     int nom_ok;
  1161.     do {
  1162.       int i;
  1163.       int len;
  1164.       len=strlen(save);    // taille
  1165.       //
  1166.       nom_ok=1;  // α priori bon
  1167.       // on part de la fin pour optimiser, plus les opti de taille pour aller encore plus vite..
  1168. #if DEBUG_SAVENAME
  1169. printf("\nStart search\n");
  1170. #endif
  1171.  
  1172. #if HTS_HASH
  1173.       i=hash_read(hash,save,"",0,0);      // lecture type 0 (sav)
  1174.       if (i>=0)
  1175. #else
  1176.       for(i=lien_tot-1;i>=0;i--) {
  1177. #if DEBUG_SAVENAME
  1178. printf("%cParse: %d",13,i);
  1179. #endif
  1180.         
  1181.         if (liens[i]->sav_len==len) {    // mΩme taille de chaεne          
  1182. #if HTS_CASSE
  1183.           if (strcmp(liens[i]->sav,save)==0)    // existe dΘja
  1184. #else
  1185.           if (strfield2(liens[i]->sav,save))    // un tel nom existe dΘja
  1186. #endif
  1187. #endif
  1188.           {
  1189. #if HTS_CASSE
  1190.             if ((strcmp(liens[i]->adr,adr)==0) && (strcmp(liens[i]->fil,fil_complete)==0))
  1191. #else
  1192.             if ((strfield2(liens[i]->adr,adr)) && (strfield2(liens[i]->fil,fil_complete)))
  1193. #endif
  1194.             {    // ok c'est le mΩme lien, adresse dΘja dΘfinie
  1195.               //printf("Ok, %s\n",save);
  1196.               //i=lien_tot;    // sortir
  1197.               i=0;
  1198. #if DEBUG_SAVENAME
  1199. printf("\nOK ALREADY DEFINED\n",13,i);
  1200. #endif
  1201.             } else {  // utilisΘ par un AUTRE, changer de nom
  1202.               char tempo[HTS_URLMAXSIZE*2];
  1203.               char* a=save+strlen(save)-1;
  1204.               char* b;
  1205.               int n=2;       
  1206.               tempo[0]='\0';
  1207.  
  1208. #if DEBUG_SAVENAME
  1209. printf("\nWRONG CASE UNMATCH : \n%s\n%s, REDEFINE\n",liens[i]->fil,fil_complete);
  1210. #endif
  1211.               nom_ok=0;
  1212.               i=0;
  1213.               
  1214.               while(( a > save) && (*a!='.') && (*a!='\\') && (*a!='/')) a--;
  1215.               if (*a=='.')
  1216.                 strncatbuff(tempo,save,(int) (a - save));
  1217.               else
  1218.                 strcatbuff(tempo,save);
  1219.               
  1220.               // tester la prΘsence d'un -xx (ex: index-2.html -> index-3.html)
  1221.               b=tempo+strlen(tempo)-1;
  1222.               while (isdigit((unsigned char)*b)) b--;
  1223.               if (*b=='-') {
  1224.                 sscanf(b+1,"%d",&n);
  1225.                 *b='\0';    // couper
  1226.                 n++;  // plus un
  1227.               }
  1228.               
  1229.               // en plus il faut gΘrer le 8-3 .. pas facile le client
  1230.               if (opt->savename_83) {
  1231.                 int max;
  1232.                 char* a=tempo+strlen(tempo)-1;
  1233.                 while(( a > tempo) && (*a!='/')) a--;
  1234.                 if (*a=='/') a++;
  1235.                 max=max_char-1-nombre_digit(n);
  1236.                 if ((int) strlen(a)>max)
  1237.                   *(a+max)='\0';  // couper sinon il n'y aura pas la place!
  1238.               }
  1239.               
  1240.               // ajouter -xx (ex: index.html -> index-2.html)
  1241.               sprintf(tempo+strlen(tempo),"-%d",n);
  1242.               
  1243.               // ajouter extension
  1244.               if (*a=='.')
  1245.                 strcatbuff(tempo,a);
  1246.               
  1247.               strcpybuff(save,tempo);
  1248.               
  1249.               //printf("switched: %s\n",save);
  1250.               
  1251.             }  // if
  1252. #if HTS_HASH
  1253.           }
  1254. #else
  1255.           }  // if
  1256.         }  // if sav_len
  1257.       }  // for
  1258. #endif
  1259. #if DEBUG_SAVENAME
  1260. printf("\nEnd search, %s\n",fil_complete);
  1261. #endif
  1262.     } while(!nom_ok);
  1263.     
  1264.   }
  1265.   
  1266.   //printf("'%s' %s %s\n",save,adr,fil);
  1267.       
  1268.   return 0;
  1269. }
  1270.  
  1271. /* nom avec md5 urilisΘ partout */
  1272. void standard_name(char* b,char* dot_pos,char* nom_pos,char* fil_complete,int short_ver) {
  1273.   b[0]='\0';
  1274.   /* Nom */
  1275.   if (dot_pos) {
  1276.     if (!short_ver)    // Noms longs
  1277.       strncatbuff(b,nom_pos,(int) (dot_pos - nom_pos));
  1278.     else
  1279.       strncatbuff(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  1280.   } else {
  1281.     if (!short_ver)    // Noms longs
  1282.       strcatbuff(b,nom_pos);
  1283.     else
  1284.       strncatbuff(b,nom_pos,8);
  1285.   }
  1286.   /* MD5 - 16 bits */
  1287.   strncatbuff(b,url_md5(fil_complete),4);
  1288.   /* Ext */
  1289.   if (dot_pos) {
  1290.     strcatbuff(b,".");
  1291.     if (!short_ver)    // Noms longs
  1292.       strcatbuff(b,dot_pos+1);
  1293.     else
  1294.       strncatbuff(b,dot_pos+1,3);
  1295.   } else {
  1296.     if (!short_ver)    // Noms longs
  1297.       strcatbuff(b,DEFAULT_EXT);    // pas de..
  1298.     else
  1299.       strcatbuff(b,DEFAULT_EXT_SHORT);    // pas de..
  1300.   }
  1301. }
  1302.  
  1303.  
  1304. /* Petit md5 */
  1305. char* url_md5(char* fil_complete) {
  1306.   char* digest;
  1307.   char* a;
  1308.   NOSTATIC_RESERVE(digest, char, 32+2);
  1309.   digest[0]='\0';
  1310.   a=strchr(fil_complete,'?');
  1311.   if (a) {
  1312.     if (strlen(a)) {
  1313.       char buff[HTS_URLMAXSIZE*2];
  1314.       a++;
  1315.       digest[0]=buff[0]='\0';
  1316.       strcatbuff(buff,a);         /* query string MD5 */
  1317.       domd5mem(buff,strlen(buff),digest,1);
  1318.     }
  1319.   }
  1320.   return digest;
  1321. }
  1322.  
  1323. // interne α url_savename: ajoute une chaεne α une autre avec \ -> /
  1324. void url_savename_addstr(char* d,char* s) {
  1325.   int i=strlen(d);
  1326.   while(*s) {
  1327.     if (*s=='\\')  // remplacer \ par des /
  1328.       d[i++]='/';
  1329.     else
  1330.       d[i++]=*s;
  1331.     s++;
  1332.   }
  1333.   d[i]='\0';
  1334. }
  1335.  
  1336. #undef test_flush
  1337.